use std::collections::HashMap;

use hyper::{Body, Method, Request as _Request, Response as _Response, StatusCode};

type Request = _Request<Body>;
type Response = _Response<Body>;

pub type Handler = fn(Request) -> Response;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct RouteKey {
    method: Method,
    pattern: String,
}

pub struct Router {
    handlers: HashMap<RouteKey, Handler>,
}

impl Router {
    pub fn new() -> Self {
        Self {
            handlers: HashMap::new(),
        }
    }

    pub fn add_route(&mut self, method: Method, pattern: impl Into<String>, handler: Handler) {
        let pattern = pattern.into();
        info!("Route {} - {}", method, pattern);
        let key = RouteKey { method, pattern };
        self.handlers.insert(key, handler);
    }

    pub fn get(&mut self, pattern: impl Into<String>, handler: Handler) {
        self.add_route(Method::GET, pattern, handler)
    }

    pub fn post(&mut self, pattern: impl Into<String>, handler: Handler) {
        self.add_route(Method::POST, pattern, handler)
    }

    pub fn handle(&self, req: Request) -> Response {
        let key = RouteKey {
            method: req.method().clone(),
            pattern: req.uri().path().into(),
        };
        if let Some(handler) = self.handlers.get(&key) {
            handler(req)
        } else {
            Response::new(format!("404 NOT FOUND: {}", req.uri().path()).into())
        }
    }
}
